/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com */

/*
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "style.h"



namespace tri {
namespace ui {

extStyle::extStyle(){
}

std::map<std::string,extStyle> extStyle::mGlobalStyles;

void extStyle::clear(){
	mDefaultState.clear();
	mMouseOverState.clear();
	mPressedState.clear();
	mDragState.clear();
	mFocusState.clear();
	mDisabledState.clear();
	mCheckedState.clear();
}

void extStyle::copy(extStyle* style){
	mDefaultState.copy(&style->mDefaultState);
	mMouseOverState.copy(&style->mMouseOverState);
	mPressedState.copy(&style->mPressedState);
	mDragState.copy(&style->mDragState);
	mFocusState.copy(&style->mFocusState);
	mCheckedState.copy(&style->mCheckedState);
	mDisabledState.copy(&style->mDisabledState);
}

void extStyle::setBGImage(std::string image,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mBGImage = image;
	}
}

extStyle::extState* extStyle::getState(int event){
	switch(event){
	case tri::NONE:
		return &mDefaultState;
		break;
	case tri::MOUSE_OVER:
		return &mMouseOverState;
		break;
	case tri::BUTTON_PRESSED:
	case tri::PRESSED:
		return &mPressedState;
		break;
	case tri::MOUSE_DRAG:
		return &mDragState;
		break;
	case tri::FOCUS:
		return &mFocusState;
		break;
	case tri::CHECKED:
		return &mCheckedState;
		break;
	case tri::DISABLED:
		return &mDisabledState;
		break;
	default:
		return &mDefaultState;
		break;
	};
	
	return &mDefaultState;
}

std::string extStyle::getBGImage(int event){
	return getState(event)->mBGImage;
}

tri::graphics::TColor extStyle::getColor(int event){
	return getState(event)->mColor;
}

void extStyle::setSegmentInsets(float l, float t, float r, float b,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mSegmentInsets.setValue(l,t,r,b);
	}
}

void extStyle::getStateGroup(std::vector<extState*>& states,int event){
	states.clear();
	switch(event){
	case tri::NONE:
		states.push_back(&mDefaultState);
		states.push_back(&mMouseOverState);
		states.push_back(&mPressedState);
		states.push_back(&mDragState);
		states.push_back(&mFocusState);
		states.push_back(&mCheckedState);
		states.push_back(&mDisabledState);
		break;
	case tri::MOUSE_OVER:
		states.push_back(&mMouseOverState);
		break;
	case tri::BUTTON_PRESSED:
	case tri::PRESSED:
		states.push_back(&mPressedState);
		states.push_back(&mDragState);
		//mFocusState.mSegmentInsets.setValue(l,t,r,b);
		break;
	case tri::MOUSE_DRAG:
		states.push_back(&mDragState);
		break;
	case tri::FOCUS:
		states.push_back(&mFocusState);
		states.push_back(&mCheckedState);
		break;
	case tri::CHECKED:
		states.push_back(&mCheckedState);
		break;
	case tri::DISABLED:
		states.push_back(&mDisabledState);
		break;
	};
	
}

tri::TRectangle* extStyle::getSegmentInsets(int event){
	return &getState(event)->mSegmentInsets;
}

void extStyle::setTransitionTime(float t,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mAnimationTime=t;
	}
	
}

void extStyle::setImageInsets(float l, float t, float r, float b,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mImageInsets.setValue(l,t,r,b);
	}
}

tri::TRectangle* extStyle::getImageInsets(int event){
	return &getState(event)->mImageInsets;
}

void extStyle::setInsets(float l, float t, float r, float b,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mInsets.setValue(l,t,r,b);
	}
}

tri::TRectangle* extStyle::getInsets(int event){
	return &getState(event)->mInsets;
}

void extStyle::setColor(int r, int g, int b, int a,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mColor.setValue(r,g,b,a);//,mDefaultState.mAnimationTime);
	}
}


int extStyle::getTextAlignment(int event ){
	return getState(event)->mTextAlignment;
}

void extStyle::setTextAlignment(int a,int event ){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mTextAlignment = a;
	}
}

extStyle::extState::extState(){
	clear();
}

void extStyle::extState::clear(){
	mBGImage = "";
	mAnimationTime = 0.0;
	mColor.setValue(255,255,255,255);
	mTextColor.setValue(0,0,0,255);
	mTextBGColor.setValue(0,0,0,0);
	mFontSize=12;
	mCharacterHeight=1;
	mFont="times.ttf";
	mImageInsets.setValue(0,0,0,0);
	mInsets.setValue(0,0,0,0);
	mSegmentInsets.setValue(0,0,0,0);
	mTextAlignment = ALIGN_LEFT;
}

void  extStyle::extState::copy(extState* state){
	state->mBGImage = mBGImage;
	state->mAnimationTime = mAnimationTime;
	state->mColor.setValue(mColor.asRGBA());
	state->mTextColor.setValue(mTextColor.asRGBA());
	state->mTextBGColor.setValue(mTextBGColor.asRGBA());
	state->mFontSize=mFontSize;
	state->mCharacterHeight=mCharacterHeight;
	state->mFont=mFont;
	state->mImageInsets = mImageInsets;
	state->mInsets = mInsets;
	state->mSegmentInsets = mSegmentInsets;
	state->mTextAlignment = mTextAlignment;
}

bool extStyle::exists(std::string key){
	return extStyle::mGlobalStyles.count(key)>0;
}

void extStyle::createStyle(std::string key){
	if(!extStyle::exists(key) && key!=""){
		extStyle::mGlobalStyles[key] = extStyle();
	}
}
	
extStyle* extStyle::getStyle(std::string key){
	if(!extStyle::exists(key) || key == ""){
		return NULL;
	}
	
	return &extStyle::mGlobalStyles[key];
}

tri::graphics::TColor extStyle::getTextColor(int event){
	return getState(event)->mTextColor;
}

void extStyle::setTextColor(int r, int g, int b, int a,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mTextColor.setValue(r,g,b,a);//,mDefaultState.mAnimationTime);
	}
}

tri::graphics::TColor extStyle::getTextBGColor(int event){
	return getState(event)->mTextBGColor;
}

void extStyle::setTextBGColor(int r, int g, int b, int a,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mTextBGColor.setValue(r,g,b,a);//,mDefaultState.mAnimationTime);
	}
}

int extStyle::getFontSize(int event  ){
	return getState(event)->mFontSize;
}

void extStyle::setFontSize(int fs,int event ){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mFontSize = fs;
	}
}
	
float extStyle::getCharacterHeight(int event ){
	return getState(event)->mCharacterHeight;
}

void extStyle::setCharacterHeight(float ch,int event ){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mCharacterHeight = ch;
	}
}
	
std::string extStyle::getFont(int event){
	return getState(event)->mFont;
}

void extStyle::setFont(std::string f,int event){
	std::vector<extState*> states;
	getStateGroup(states,event);
	for (unsigned int i=0; i< states.size();i++){
		states[i]->mFont = f;
	}
}

void loadStyleFromXML(std::string xmlfile){
	tri::TXMLDoc doc;
	tri::ui::extStyle* style = NULL;
	
	doc.load(xmlfile.c_str());
	
	if(doc.hasElement("style_doc")){
		
		tri::TXMLNode* style_doc = doc.getElement("style_doc");
		
		int styleCount = style_doc->countElement("style");
		for (int i=0; i < styleCount; i++){
			tri::TXMLNode* style_node = style_doc->getElement("style",i);
			
			
			
			if(style_node->hasAttribute("name")){
				std::string style_name = style_node->getAttribute<std::string>("name");
				
				
				style = tri::ui::extStyle::getStyle(style_name);
				
				if(style==NULL){
					tri::ui::extStyle::createStyle(style_name);
				}
				style = tri::ui::extStyle::getStyle(style_name);
				
				if(style_node->hasAttribute("clear")){
					std::string style_clear = style_node->getAttribute<std::string>("clear");
					if(style_clear=="1" || style_clear == "true"){
						style->clear();
					}else if(style_clear!="0" && style_clear != "false"){
						tri::LOG_SEVERE(xmlfile+" : Style \"clear\" attribute must be \"0\",\"1\",\"false\" or \"true\".");
						throw tri::TriException(xmlfile+" : Style must contain a \"name\" attribute.");
					}
				}
				
			}else{
				tri::LOG_SEVERE(xmlfile+" : Style must contain a \"name\" attribute.");
				throw tri::TriException(xmlfile +" : Style must contain a \"name\" attribute.");
			}
			
			loadXMLState(xmlfile,style,style_node,tri::NONE);
			
			if(style_node->hasElement("state")){
				int state_count = style_node->countElement("state");
				tri::TXMLNode* state_node = NULL;
				
				for(int state_index = 0; state_index < state_count ; state_index++){
					state_node = style_node->getElement("state",state_index);
					if(state_node->hasAttribute("value")){
						if(state_node->getAttribute<std::string>("value")=="MOUSE_OVER"){
							loadXMLState(xmlfile,style,state_node,tri::MOUSE_OVER);
							break;
						}else if(state_node->getAttribute<std::string>("value")=="PRESSED"){
							loadXMLState(xmlfile,style,state_node,tri::BUTTON_PRESSED);
							break;
						}else if(state_node->getAttribute<std::string>("value")=="CLICKED"){
							loadXMLState(xmlfile,style,state_node,tri::BUTTON_CLICKED);
							break;
						}else if(state_node->getAttribute<std::string>("value")=="FOCUS"){
							loadXMLState(xmlfile,style,state_node,tri::FOCUS);
							break;
						}else if(state_node->getAttribute<std::string>("value")=="DISABLED"){
							loadXMLState(xmlfile,style,state_node,tri::DISABLED);
							break;
						}
					}else{
						std::string msg  = xmlfile+" : \"state\" must contain attribute value";
						tri::LOG_SEVERE(msg);
						throw tri::TriException(msg);
					}
					
				}
			}
		}
		
	}
	
//	std::cout<<doc.getType()<<std::endl;
//	std::cout<<doc.hasElement("style_doc")<<std::endl;
//	std::cout<<doc.getElement("style_doc")->getType()<<std::endl;
}


void loadXMLState(std::string xmlfile,tri::ui::extStyle* style,tri::TXMLNode* node,int state){
	if(node->hasElement("color")){
		tri::TXMLNode* color = node->getElement("color");
		if(!color->hasAttribute("r") || !color->hasAttribute("g") || !color->hasAttribute("b")){
			std::string msg  = xmlfile+" : \"color\" must contain attributes r, g, and b. a is optional and defaults to 255 if not specified.";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		int a = 255;
		if(color->hasAttribute("a")){
			a = color->getAttribute<int>("a");
		}
		
		style->setColor(color->getAttribute<int>("r"),color->getAttribute<int>("g"),color->getAttribute<int>("b"),a,state);
	}
	
	
	if(node->hasElement("image")){
		tri::TXMLNode* image_node = node->getElement("image");
		if(!image_node->hasAttribute("value")){
			std::string msg  = xmlfile+" : \"image\" must contain attributes value.";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		std::string image = image_node->getAttribute<std::string>("value");
		style->setBGImage(image,state);
	}
	
	if(node->hasElement("insets")){
		tri::TXMLNode* insets = node->getElement("insets");
		if(!insets->hasAttribute("l") || !insets->hasAttribute("t") || !insets->hasAttribute("r") || !insets->hasAttribute("b")){
			std::string msg  = xmlfile+" : \"insets\" must contain attributes l,t,r,b";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		style->setInsets(insets->getAttribute<int>("l"),insets->getAttribute<int>("t"),insets->getAttribute<int>("r"),insets->getAttribute<int>("b"),state);
	}
	
	if(node->hasElement("imageInsets")){
		tri::TXMLNode* insets = node->getElement("imageInsets");
		if(!insets->hasAttribute("l") || !insets->hasAttribute("t") || !insets->hasAttribute("r") || !insets->hasAttribute("b")){
			std::string msg  = xmlfile+" : \"imageInsets\" must contain attributes l,t,r,b";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		style->setImageInsets(insets->getAttribute<int>("l"),insets->getAttribute<int>("t"),insets->getAttribute<int>("r"),insets->getAttribute<int>("b"),state);
	}
	
	if(node->hasElement("segmentInsets")){
		tri::TXMLNode* insets = node->getElement("segmentInsets");
		if(!insets->hasAttribute("l") || !insets->hasAttribute("t") || !insets->hasAttribute("r") || !insets->hasAttribute("b")){
			std::string msg  = xmlfile+" : \"segmentInsets\" must contain attributes l,t,r,b";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		style->setSegmentInsets(insets->getAttribute<int>("l"),insets->getAttribute<int>("t"),insets->getAttribute<int>("r"),insets->getAttribute<int>("b"),state);
	}
	
	if(node->hasElement("font")){
		tri::TXMLNode* font_node = node->getElement("font");
		if(!font_node->hasAttribute("size") || !font_node->hasAttribute("name") || !font_node->hasAttribute("char_height")){
			std::string msg  = xmlfile+" : \"font\" must contain attributes name, size and char_height.";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		int size = font_node->getAttribute<int>("size");
		float char_height = font_node->getAttribute<float>("char_height");
		std::string name = font_node->getAttribute<std::string>("name");
		
		style->setCharacterHeight(char_height);
		style->setFontSize(size);
		style->setFont(name);
		
		if(font_node->hasAttribute("text_alignment")){
			std::string align = font_node->getAttribute<std::string>("text_alignment");
			if(align == "CENTER"){
				style->setTextAlignment(tri::ui::ALIGN_CENTER,state);
			}else if(align == "LEFT"){
				style->setTextAlignment(tri::ui::ALIGN_LEFT,state);
			}else if(align == "RIGHT"){
				style->setTextAlignment(tri::ui::ALIGN_RIGHT,state);
			}
		}
	}
	
	if(node->hasElement("text_color")){
		tri::TXMLNode* color = node->getElement("text_color");
		if(!color->hasAttribute("r") || !color->hasAttribute("g") || !color->hasAttribute("b")){
			std::string msg  = xmlfile+" : \"text_color\" must contain attributes r, g, and b. a is optional and defaults to 255 if not specified.";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		int a = 255;
		if(color->hasAttribute("a")){
			a = color->getAttribute<int>("a");
		}
		
		style->setTextColor(color->getAttribute<int>("r"),color->getAttribute<int>("g"),color->getAttribute<int>("b"),a,state);
	}
	
	if(node->hasElement("text_background_color")){
		tri::TXMLNode* color = node->getElement("text_background_color");
		if(!color->hasAttribute("r") || !color->hasAttribute("g") || !color->hasAttribute("b")){
			std::string msg  = xmlfile+" : \"text_background_color\" must contain attributes r, g, and b. a is optional and defaults to 255 if not specified.";
			tri::LOG_SEVERE(msg);
			throw tri::TriException(msg);
		}
		
		int a = 255;
		if(color->hasAttribute("a")){
			a = color->getAttribute<int>("a");
		}
		
		style->setTextBGColor(color->getAttribute<int>("r"),color->getAttribute<int>("g"),color->getAttribute<int>("b"),a,state);
	}
}

}// namspace ui
}//namespace tri

